#include "../src/ConfigReader.hpp"
#include "../src/dbusServer.hpp"
#include "../src/FileManager.hpp"
#include "../src/SQLAction.hpp"
#include "../src/dbusClient.hpp"
#include <filesystem>
#include <spdlog/spdlog.h>

dbusServer* ptrDbusServer;
FileManager* ptrFileManager;
SQLAction* ptrSQLAction;


long CreateTask(std::string name)
{
  long resid;
  try
  {
    resid=ptrSQLAction->CreateTask(name);
  }
  catch(const std::runtime_error& e)
  {
    dbusServer::ThrowError("无法创建任务");
    spdlog::error("无法创建任务");
  }
  return resid;
}

void DeleteTask(long id)
{
  try
  {
    ptrSQLAction->DeleteTask(id);
  }
  catch(const std::runtime_error& e)
  {
    dbusServer::ThrowError("无法删除任务");
    spdlog::error("无法删除任务");
  }
}


std::deque<DB_TaskInf> taskInfList;

void LoadTaskInf()
{
  try
  {
    //SQL操作中的GetTaskInf是用来获取任务ID
    taskInfList=ptrSQLAction->GetTaskInf();
  }
  catch(const std::runtime_error& e)
  {
    dbusServer::ThrowError("无法获取任务ID列表");
    spdlog::error("无法获取任务ID");
  }
}

std::tuple<std::string,std::string> GetTaskInf(long id)
{
  auto ret = std::find_if(taskInfList.begin(),taskInfList.end(),[&id](DB_TaskInf val){
    if(id==val.id)
      return true;
    else
      return false;
  });
  if(ret==taskInfList.end())
    throw sdbus::Error("Can't find this id");
  return std::make_tuple(ret->name,ret->createTime);
}

std::vector<long> GetRecordFinishHandleList()
{
  std::vector<long> ret;
  auto handleList=ptrSQLAction->GetHandleIDList();
  ret.reserve(handleList.size());
  for(int i=0;i<handleList.size();i++)
    ret[i]=handleList[i];
  return ret;
}

std::vector<long> GetTaskIDList()
{
  std::vector<long> res;
  res.reserve(taskInfList.size());
  for(const auto & i : taskInfList)
    res.push_back(i.id);
  return res;
}

std::vector<std::string> GetTaskNameList()
{
  std::vector<std::string> res;
  res.reserve(taskInfList.size());
  for(const auto & i : taskInfList)
    res.push_back(i.name);
  return res;
}

std::vector<long> GetRecordIDList(long task_id)
{
  std::deque<long> value;
  try
  {
    value=ptrSQLAction->GetRecordIDList(task_id);
  }
  catch(std::exception& e)
  {
    dbusServer::ThrowError(e.what());
  }
  std::vector<long> res;
  res.reserve(value.size());
  for(const auto & i : value)
    res.push_back(i);
  return res;
}

std::tuple<long,long,std::string,bool,bool> GetRecordInf(long id)
{
  try
  {
    return ptrSQLAction->GetRecordInf(id);
  }
  catch(const std::exception& e)
  {
    dbusServer::ThrowError(e.what());
    throw; //没啥用，但是能减少clang警告
  }
}

long CreateRecord(long task_id,long stu_id)
{
  long id;
  try
  {
    id=ptrSQLAction->CreateRecord(stu_id,task_id);
  }
  catch(const std::exception & e)
  {
    dbusServer::ThrowError(e.what());
  }
  if(!ptrFileManager->CreateRecord(id))
  {
    //撤销记录
    ptrSQLAction->DeleteRecord(id);
    //抛出异常
    dbusServer::ThrowError("无法创建录制目录");
    spdlog::error("无法创建录制目录");
  }
  return id;
}

void FinishRecord(long rec_id)
{
  if(!ptrFileManager->CheckRecordFinish(rec_id))
    dbusServer::ThrowError("无法验证录制文件");
  ptrSQLAction->RecordFinish(rec_id);
}

std::string GetRecordPath(long id)
{
  return ptrFileManager->GetRecordPath(id);
}

bool CheckStudentExists(long id)
{
  return ptrSQLAction->CheckStudentExists(id);
}

std::string GetStudentInf(long id)
{
  return ptrSQLAction->GetStudentInf(id);
}

std::vector<long> GetRecordFinishHandleListWithTask(long id)
{
  return ptrSQLAction->GetHandleIDListWithTask(id);
}

bool OutputData(long id,std::string target) {
  std::tuple<long,long,std::string,bool,bool> inf;
  try {
    inf=ptrSQLAction->GetRecordInf(id);
  } catch (const std::exception& e) {
    return false;
  }
  std::string sourceDir=GetRecordPath(id);
  if(!std::filesystem::exists(sourceDir))
    return false;
  std::filesystem::path targetDir=fmt::format("{}/{}_{}",target,std::get<0>(inf),std::get<2>(inf));
  if(!std::filesystem::create_directory(targetDir))
    return false;
  for (auto const& dir_entry : std::filesystem::directory_iterator{GetRecordPath(id)})
  {
    if(std::filesystem::is_regular_file(dir_entry))
       std::filesystem::copy_file(dir_entry,targetDir/dir_entry.path().filename());
  }
  return true;
}

int main()
{
  {
    ConfigReader config;
    std::vector<std::string> cVector;
    auto cList=config.GetCameraList();
    cVector.reserve(cList.size());
    for(const auto & i : cList)
      cVector.push_back(i);
    ptrFileManager=new FileManager(config.GetDataRootPath(),cVector);
    ptrSQLAction=new SQLAction("hbty","hbty",config.GetPGIpAddress(),"hbty");
  }
  ptrDbusServer=new dbusServer();
  ptrDbusServer->funcCreateTask=CreateTask;
  ptrDbusServer->funcDeleteTask=DeleteTask;
  ptrDbusServer->funcGetTaskIDList=GetTaskIDList;
  ptrDbusServer->funcGetTaskNameList=GetTaskNameList;
  ptrDbusServer->funcGetRecordInf=GetRecordInf;
  ptrDbusServer->funcLoadTaskInf=LoadTaskInf;
  ptrDbusServer->funcFinishRecord=FinishRecord;
  ptrDbusServer->funcGetRecordPath=GetRecordPath;
  ptrDbusServer->funcCheckStudentExists=CheckStudentExists;
  ptrDbusServer->funcGetStudentInf=GetStudentInf;
  ptrDbusServer->funcCreateRecord=CreateRecord;
  ptrDbusServer->funcGetRecordFinishHandleList=GetRecordFinishHandleList;
  ptrDbusServer->funcGetTaskInf=GetTaskInf;
  ptrDbusServer->funcGetRecordFinishHandleListWithTask=GetRecordFinishHandleListWithTask;
  ptrDbusServer->funcOutputData=OutputData;
  ptrDbusServer->Boot();

  while(sleep(10)==0)
    ;

  delete ptrDbusServer;
  delete ptrFileManager;
  delete ptrSQLAction;
}
